package com.zhiche.lisa.bms.service.contract.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zhiche.lisa.bms.dao.mapper.contract.ContractMapper;
import com.zhiche.lisa.bms.dao.model.charge.ChargeOffRule;
import com.zhiche.lisa.bms.dao.model.contract.Contract;
import com.zhiche.lisa.bms.dao.model.contract.ContractAccessory;
import com.zhiche.lisa.bms.dao.model.contract.ContractFleetDtl;
import com.zhiche.lisa.bms.dao.model.fee.FeePayable;
import com.zhiche.lisa.bms.dao.model.prepay.PrepayBill;
import com.zhiche.lisa.bms.dao.model.quote.Quote;
import com.zhiche.lisa.bms.dao.model.quote.QuoteDtl;
import com.zhiche.lisa.bms.enums.ChargeOffRuleEnum;
import com.zhiche.lisa.bms.enums.FleetAttributeEnum;
import com.zhiche.lisa.bms.pojo.dto.util.mdm.ServiceTypeDTO;
import com.zhiche.lisa.bms.pojo.vo.common.AttachDetailVO;
import com.zhiche.lisa.bms.pojo.vo.contract.ContractAccessoryVO;
import com.zhiche.lisa.bms.pojo.vo.contract.ContractAndFinalpayVO;
import com.zhiche.lisa.bms.pojo.vo.contract.ContractVO;
import com.zhiche.lisa.bms.pojo.vo.contract.PrintContractVO;
import com.zhiche.lisa.bms.pojo.vo.quote.QuoteAndDtlVO;
import com.zhiche.lisa.bms.pojo.vo.quote.QuoteCommonVO;
import com.zhiche.lisa.bms.pojo.vo.quote.QuoteDtlAndFeeVO;
import com.zhiche.lisa.bms.service.charge.ChargeOffRuleService;
import com.zhiche.lisa.bms.service.contract.ContractFleetDtlService;
import com.zhiche.lisa.bms.service.contract.ContractService;
import com.zhiche.lisa.bms.service.fee.FeePayableService;
import com.zhiche.lisa.bms.service.prepay.PrepayBillService;
import com.zhiche.lisa.bms.service.quote.QuoteDtlService;
import com.zhiche.lisa.bms.service.quote.QuoteService;
import com.zhiche.lisa.bms.service.utils.MdmUtil;
import com.zhiche.lisa.bms.service.utils.common.AccountBindUtil;
import com.zhiche.lisa.bms.service.utils.common.UploadUtil;
import com.zhiche.lisa.bms.service.utils.common.identityCodeUtil.CodeUtil;
import com.zhiche.lisa.core.supports.BaseException;
import com.zhiche.lisa.core.utils.Account.AccountUtil;
import com.zhiche.lisa.core.utils.Account.JwtAccountVO;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.*;


/**
 * <p>
 * 合同主表 服务实现类
 * </p>
 *
 * @author liuanshun
 * @since 2018-10-23
 */
@Service
public class ContractServiceImpl extends ServiceImpl<ContractMapper, Contract> implements ContractService {

    private static final Logger LOGGER = LoggerFactory.getLogger(ContractServiceImpl.class);

    @Autowired
    private ContractAccessoryServiceImpl contractAccessoryService;
    @Autowired
    private ContractFleetDtlService contractFleetDtlService;
    @Autowired
    private UploadUtil uploadUtil;
    @Autowired
    private QuoteService quoteService;
    @Autowired
    private QuoteDtlService quoteDtlService;
    @Autowired
    private CodeUtil codeUtil;
    @Autowired
    private FeePayableService feePayableService;
    @Autowired
    private MdmUtil mdmUtil;
    @Autowired
    private ChargeOffRuleService chargeOffRuleService;

    @Autowired
    private PrepayBillService prepayBillService;


    private final Map<String, String> contractCodeMapping = new HashMap<String, String>();

    //初始化CCN映射结果
    {
        contractCodeMapping.put("中联物流（中国）有限公司", "UNLCN");
        contractCodeMapping.put("测试承运商", "CESHI");
        contractCodeMapping.put("重庆分公司", "UNLCN-CQ");
        contractCodeMapping.put("湖南分公司", "UNLCN-HN");
        contractCodeMapping.put("江西分公司", "UNLCN-JX");
        contractCodeMapping.put("九江分公司", "UNLCN-JJ");
        contractCodeMapping.put("景德镇分公司", "UNLCN-JDZ");
        contractCodeMapping.put("江西诺信物流有限公司", "UNLCN-JXNX");
        contractCodeMapping.put("南昌中经物流有限公司", "UNLCN-NCZJ");
        contractCodeMapping.put("江西中联智能物流有限公司", "UNLCN-JXZN");
        contractCodeMapping.put("江西迅佳物流有限公司", "UNLCN-JXXJ");
        contractCodeMapping.put("江西路易通达运输有限公司", "LYTD");
        contractCodeMapping.put("景德镇久顺途运输有限公司", "JST");
        contractCodeMapping.put("江西佳迅运输有限公司", "JX");
        contractCodeMapping.put("鹰潭运捷运输有限公司", "YTYJ");
    }


    private Contract bindContractByContractFleetDtls(List<ContractFleetDtl> contractFleetDtls, Contract contract) {
        //根据详明寻找绑定车队id和name
        List<String> fleetNames = new ArrayList<>();
        List<String> fleetIds = new ArrayList<>();

        if (!CollectionUtils.isEmpty(contractFleetDtls)) {
            if (contract.getIsPrepay() == null) {
                Integer isPrepay = contractFleetDtls.get(0).getIsPrepay();
                contract.setIsPrepay(isPrepay == null ? 1 : isPrepay);
            }
            boolean areTemporaryContract = Objects.deepEquals(new Integer(0), contract.getContractType());
            contractFleetDtls.forEach(contractFleetDtl -> {
                if (!areTemporaryContract) {
                    this.checkOillAndCashRateSum(contractFleetDtl);
                }
                fleetIds.add(contractFleetDtl.getFleetId() == null ? "" : contractFleetDtl.getFleetId().toString());
                fleetNames.add(contractFleetDtl.getFleetName());
            });
        }
        contract.setFleetIdList(fleetIds.toArray(new String[fleetIds.size()]));
        contract.setFleetNameList(fleetNames.toArray(new String[fleetNames.size()]));
        return contract;
    }

    /**
     * 根据分页条件获取分页合同数据
     *
     * @param pageParam
     * @return
     */
    @Override
    public Page<Contract> selectContractPage(Page<Contract> pageParam) {
        EntityWrapper<Contract> contractEntityWrapper = this.bindContractWapper(pageParam.getCondition());
        return selectPage(pageParam.setCondition(new HashMap<>()), contractEntityWrapper);
    }

    /**
     * 根据条件获取合同信息
     *
     * @param condition
     * @return
     */
    @Override
    public List<Contract> selectContractList(Map<String, Object> condition) {
        EntityWrapper<Contract> contractEntityWrapper = this.bindContractWapper(condition);
        return selectList(contractEntityWrapper);
    }

    /**
     * 根据条件获取合同信息
     *
     * @param condition
     * @return
     */
    @Override
    public List<Contract> selectContractListNoTenant(Map<String, Object> condition) {
        EntityWrapper<Contract> contractEntityWrapper = this.bindContractWapper(condition);
        return baseMapper.selectListNoTenant(contractEntityWrapper);
    }

    /**
     * 根据车队id查找匹配合同
     *
     * @param fleetId
     * @return
     */
    @Override
    public List<Contract> getContractAreExamineListByFleetId(Long fleetId, String queryType) {
        EntityWrapper<Contract> entityWrapper = new EntityWrapper<>();
        entityWrapper.eq("second_party_type", "1");
        entityWrapper.eq("cont_state", 2);
        entityWrapper.andNew().eq("fleet_type_id", fleetId).or().like("fleet_ids", String.valueOf(fleetId));
        if (!Strings.isNullOrEmpty(queryType)) {
            if ("MaxEffectiveDate".equals(queryType)) {
                entityWrapper.orderBy("effective_date desc");
                List<Contract> contracts = this.selectList(entityWrapper);
                ArrayList<Contract> returnArray = new ArrayList<>();
                if (!CollectionUtils.isEmpty(contracts)) {
                    returnArray.add(contracts.get(0));
                }
                return returnArray;
            }
        }
        return this.selectList(entityWrapper);
    }

    /**
     * 获取报价单可绑定合同
     *
     * @return
     */
    @Override
    public List<Contract> selectQuoteCanBindContract(String fleetTypeId) {
        Map<String, Object> condition = new HashMap<String, Object>();
        condition.put("fleetIds", fleetTypeId);
        //正式合同
        condition.put("contractType", "1");
        condition.put("noFailure", "4");
        List<Contract> contracts = this.selectContractList(condition);
        List<Contract> returnContracts = new ArrayList<>();
        if (!CollectionUtils.isEmpty(contracts)) {
            contracts.forEach(contract -> {
                String[] fleetIdList = contract.getFleetIdList();
                if (ArrayUtils.contains(fleetIdList, fleetTypeId)) {
                    returnContracts.add(contract);
                }
            });
        }
        return bindDefaultVal(returnContracts);
    }

    /**
     * 报价单关联合同 - 带有效期查询
     *
     * @param quoteCommonVO
     * @return
     */
    @Override
    public List<Contract> quoteBindContract(QuoteCommonVO quoteCommonVO) {
        Map<String, Object> condition = Maps.newHashMap();
        // 车队
        condition.put("fleetIds", quoteCommonVO.getSubId());
        condition.put("effectiveDateStart", quoteCommonVO.getEffectiveDate());
        condition.put("effectiveDateEnd", quoteCommonVO.getInvalidDate());
        //正式合同
        condition.put("contractType", "1");
        condition.put("noFailure", "4");
        List<Contract> contractList = this.selectContractList(condition);
        List<Contract> returnContracts = new ArrayList<>();
        if (!CollectionUtils.isEmpty(contractList)) {
            contractList.forEach(contract -> {
                String[] fleetIdList = contract.getFleetIdList();
                if (ArrayUtils.contains(fleetIdList, String.valueOf(quoteCommonVO.getSubId()))) {
                    returnContracts.add(contract);
                }
            });
        }
        return bindDefaultVal(returnContracts);
    }

    private List<Contract> bindDefaultVal(List<Contract> contracts) {
        if (!CollectionUtils.isEmpty(contracts)) {
            contracts.forEach(contract -> {
                if (contract.getRate() == null) {
                    contract.setRate(BigDecimal.ZERO);
                }
            });
        }
        return contracts;
    }

    /**
     * 绑定分页查询条件
     *
     * @param condition
     * @return
     */
    private EntityWrapper<Contract> bindContractWapper(Map<String, Object> condition) {
        EntityWrapper<Contract> contractEntityWrapper = new EntityWrapper<>();
        if (!CollectionUtils.isEmpty(condition)) {
            contractEntityWrapper.orderBy("gmt_create desc, id desc");

            if (!StringUtils.isEmpty(condition.get("contState"))) {
                contractEntityWrapper.eq("cont_state", condition.get("contState"));
            } else {
                contractEntityWrapper.ne("cont_state", 4);
            }

            for (Map.Entry<String, Object> item :
                    condition.entrySet()) {
                if ("noFailure".equals(item.getKey())) {
                    contractEntityWrapper.ne("cont_state", "4");
                }
                if (!StringUtils.isEmpty(item.getValue())) {
                    if ("fleetTypeId".equals(item.getKey())) {
                        contractEntityWrapper.eq("fleet_type_id", item.getValue().toString());
                    }
                    if ("contractType".equals(item.getKey())) {
                        contractEntityWrapper.eq("contract_type", item.getValue());
                    }
                    if ("payDays".equals(item.getKey())) {
                        String[] str = String.valueOf(item.getValue()).trim().replace(" ", "").split(",|\n|;");
                        contractEntityWrapper.in("pay_days", str);
                    }
                    if ("fleetTypeName".equals(item.getKey())) {
                        contractEntityWrapper.eq("fleet_type_name", String.valueOf(item.getValue()));
                    }
                    if ("fleetIds".equals(item.getKey())) {
                        contractEntityWrapper.like("fleet_ids", String.valueOf(item.getValue()));
                    }
                    if ("contName".equals(item.getKey())) {
                        contractEntityWrapper.like("cont_name", String.valueOf(item.getValue()));
                    }
                    if ("contCode".equals(item.getKey())) {
                        contractEntityWrapper.like("cont_code", String.valueOf(item.getValue()));
                    }
                    if ("effectiveDate".equals(item.getKey())) {
                        contractEntityWrapper.ge("effective_date", item.getValue());
                    }
                    if ("invalidDate".equals(item.getKey())) {
                        contractEntityWrapper.le("effective_date", item.getValue());
                    }
                    if ("termOfValidity".equals(item.getKey())) {
                        contractEntityWrapper.le("effective_date", item.getValue());
                        contractEntityWrapper.ge("invalid_date", item.getValue());
                    }
                    if ("gmtCreate".equals(item.getKey())) {
                        contractEntityWrapper.ge("gmt_create", String.valueOf(item.getValue()));
                    }
                    if ("secondPartyType".equals(item.getKey())) {
                        contractEntityWrapper.eq("second_party_type", String.valueOf(item.getValue()));
                    }
                    if ("gmtModify".equals(item.getKey())) {
                        contractEntityWrapper.le("gmt_create", String.valueOf(item.getValue()));
                    }
                    if ("isPrepay".equals(item.getKey())) {
                        contractEntityWrapper.le("is_prepay", String.valueOf(item.getValue()));
                    }
                    if ("effectiveDateStart".equals(item.getKey())) {
                        contractEntityWrapper.le("effective_date", item.getValue());
                    }
                    if ("effectiveDateEnd".equals(item.getKey())) {
                        contractEntityWrapper.ge("invalid_date", item.getValue());
                    }
                }
            }
        }
        return contractEntityWrapper;
    }

    /**
     * 新增合同
     *
     * @param contract
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Contract insertContract(Contract contract) {
        if (Objects.isNull(contract)) {
            throw new BaseException("未获取合同信息");
        }
        if (contract.getContractType() == null) {
            contract.setContractType(1);
        }
        if (contract.getContState() == null) {
            contract.setContState(0L);
        }
        if (contract.getSecondPartyType() == null) {
            contract.setSecondPartyType(1);
        }
        //合同可行性校验
        checkContractEffective(contract);
        //获取创建人
        if (Objects.nonNull(contract.getTenantId())) {
            new AccountBindUtil<Contract>().bindCreatorAndTenantId(contract, false);
        } else {
            new AccountBindUtil<Contract>().bindCreatorAndTenantId(contract, true);
        }
        /*
         * 根据甲方名称选择code生成规则
         */
        Map<String, String> replaceChar = new HashMap<>();
        replaceChar.put("CCN", contractCodeMapping.get(contract.getFirstPartyName()));
        contract.setContCode(codeUtil.getContractCode().getNextCode(replaceChar));
        contract.setGmtCreate(new Date());
        this.insert(contract);
        return contract;
    }

    /**
     * 校验新增甲、乙双方的合同可行性
     *
     * @param contract
     */
    private void checkContractEffective(Contract contract) {
        if (contract.getContractType() != 1) {
            EntityWrapper<Contract> entityWrapper = new EntityWrapper<>();
            entityWrapper.eq("first_party_id", contract.getFirstPartyId());
            entityWrapper.ge("invalid_date", contract.getEffectiveDate());
            entityWrapper.ne("cont_state", 4L);
            entityWrapper.andNew().eq("fleet_type_id", contract.getFleetTypeId()).or().like("fleet_ids", String.valueOf(contract.getFleetTypeId()));
            List<Contract> list = this.selectList(entityWrapper);
            if (!CollectionUtils.isEmpty(list)) {
                throw new BaseException("新增合同生效日期在已有合同的失效日期之内");
            }
        }
    }

    /**
     * 校验油卡比例与现金比例之和是否等于1
     *
     * @param contract
     */
    private void checkOillAndCashRateSum(ContractFleetDtl contract) {
        BigDecimal a, b, c, d;
        if (contract.getOilFinalpayRate() != null) {
            a = contract.getOilFinalpayRate().setScale(2, BigDecimal.ROUND_HALF_UP);
        } else {
            a = BigDecimal.valueOf(0).setScale(2, BigDecimal.ROUND_HALF_UP);
        }
        if (contract.getOilPrepayRate() != null) {
            b = contract.getOilPrepayRate().setScale(2, BigDecimal.ROUND_HALF_UP);
        } else {
            b = BigDecimal.valueOf(0).setScale(2, BigDecimal.ROUND_HALF_UP);
        }
        if (contract.getCashFinalpayRate() != null) {
            c = contract.getCashFinalpayRate().setScale(2, BigDecimal.ROUND_HALF_UP);
        } else {
            c = BigDecimal.valueOf(0).setScale(2, BigDecimal.ROUND_HALF_UP);
        }
        if (contract.getCashPrepayRate() != null) {
            d = contract.getCashPrepayRate().setScale(2, BigDecimal.ROUND_HALF_UP);
        } else {
            d = BigDecimal.valueOf(0).setScale(2, BigDecimal.ROUND_HALF_UP);
        }
        BigDecimal sum = a.add(b).add(c).add(d);
        if (!(sum.compareTo(BigDecimal.valueOf(1)) == 0)) {
            throw new BaseException("油卡比例与现金比例之和不等于1");
        }
    }

    /**
     * 合同编辑更新
     *
     * @param contractVO
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void updateContract(ContractVO contractVO) {
        if (Objects.isNull(contractVO)) {
            throw new BaseException("未获取编辑对象");
        }
        Contract contract = contractVO.getContract();
        if (Objects.nonNull(contract)) {
//            editContractFleetDtls
            this.bindContractByContractFleetDtls(contractVO.getContractFleetDtls(), contractVO.getContract());
            contract.setGmtModify(new Date());
            List<ContractAccessory> contractAccessories = contractVO.getContractAccessories();
            //获取附件主表ID
            Long headId = contract.getId();
            //刷新编辑合同所属附件
            this.updateContractAccessory(contractAccessories, headId);
            this.updateById(contract);
            contractFleetDtlService.editContractFleetDtls(contractVO.getContractFleetDtls(), headId);

            // 校验出账规则是否时间冲突
            checkRuleDate(contract);
        }
    }

    /**
     * 刷新编辑合同所属附件
     *
     * @param contractAccessories
     * @param headId
     */
    private void updateContractAccessory(List<ContractAccessory> contractAccessories, Long headId) {
        if (!CollectionUtils.isEmpty(contractAccessories)) {
            List<Long> ids = new ArrayList<>();
            //获取需新增附件
            List<ContractAccessory> addContractAccessory = new ArrayList<>();
            contractAccessories.forEach(contractAccessory -> {
                if (contractAccessory.getId() != null) {
                    ids.add(contractAccessory.getId());
                } else {
                    contractAccessory.setHeadId(headId);
                    addContractAccessory.add(contractAccessory);
                }
            });
            EntityWrapper<ContractAccessory> entityWrapper = new EntityWrapper<>();
            entityWrapper.eq("head_id", headId);
            entityWrapper.notIn("id", ids);
            //获取需要删除附件
            List<ContractAccessory> deleteContractAccessory = contractAccessoryService.selectList(entityWrapper);
            if (!CollectionUtils.isEmpty(deleteContractAccessory)) {
                List<Serializable> id = new ArrayList<>();
                deleteContractAccessory.forEach(contractAccessory -> id.add(contractAccessory.getId()));
                contractAccessoryService.deleteBatchIds(id);
            }
            if (!CollectionUtils.isEmpty(addContractAccessory)) {
                contractAccessoryService.insertBatch(addContractAccessory);
            }
        }
    }

    /**
     * 合同提交审核
     *
     * @param ids
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void contractRequestCheck(List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            throw new BaseException("未获取申请id");
        }
        EntityWrapper<Contract> entityWrapper = new EntityWrapper<>();
        entityWrapper.in("id", ids);
        List<Contract> contracts = this.selectList(entityWrapper);
        if (!CollectionUtils.isEmpty(contracts)) {
            contracts.forEach(contract -> {
                if (Objects.nonNull(contract)) {
                    if (!(contract.getContState() == 0)) {
                        throw new BaseException(contract.getContName() + "不为新增状态合同审核失效");
                    }
                    contract.setContState(1L);
                }
            });
            this.updateBatchById(contracts);
        }
    }

    /**
     * 合同作废
     *
     * @param ids
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void contractInvalid(List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            throw new BaseException("未获取作废ids");
        }
        EntityWrapper<Contract> entityWrapper = new EntityWrapper<>();
        entityWrapper.in("id", ids);
        List<Contract> contracts = this.selectList(entityWrapper);
        if (!CollectionUtils.isEmpty(contracts)) {


            contracts.forEach(contract -> {
                if (Objects.nonNull(contract)) {
                    // if (!(contract.getContState() == 0)) {
                    //     throw new BaseException(contract.getContName() + "不为新增状态合同作废失效");
                    // }

                    // 判断应付订单是否出账
                    boolean result = validContractBill(contract.getContCode());
                    if (!result) {
                        throw new BaseException(contract.getContName() + "合同下应付订单已出账, 不可作废!");
                    }
                    contract.setContState(4L);
                    // 清空对应的数据
                    cleanFeeAndPrebill(contract.getContCode());
                }
            });
            this.updateBatchById(contracts);

        }
    }

    /**
     * 校验合同下的应付订单是否出账
     *
     * @param contractCode
     * @return
     */
    private boolean validContractBill(String contractCode) {
        boolean result = true;
        EntityWrapper<FeePayable> fee = new EntityWrapper<>();
        fee.eq("contract_code", contractCode);
        fee.ne("status", 2);
        List<FeePayable> feePayableList = feePayableService.selectList(fee);
        if (!CollectionUtils.isEmpty(feePayableList)) {
            for (FeePayable feePayable : feePayableList) {
                if (Integer.valueOf(1).equals(feePayable.getStatus())) {
                    result = false;
                    break;
                }
            }
        }
        return result;
    }

    /**
     * 清空合同数据
     *
     * @param contractCode
     */
    private void cleanFeeAndPrebill(String contractCode) {
        EntityWrapper<FeePayable> fee = new EntityWrapper<>();
        fee.eq("contract_code", contractCode);
        fee.ne("status", 2);
        List<FeePayable> feePayableList = feePayableService.selectList(fee);
        if (!CollectionUtils.isEmpty(feePayableList)) {
            List<Long> feeIdList = Lists.newArrayList();
            feePayableList.forEach(feePayable -> {
                feeIdList.add(feePayable.getId());
                // 合同号
                feePayable.setContractCode(null);
                // 合同类型
                feePayable.setContractType(null);
                // 合同价
                feePayable.setActualAmt(BigDecimal.ZERO);
                feePayable.setActualPrice(BigDecimal.ZERO);
                // 预付
                feePayable.setCashBaPay(BigDecimal.ZERO);
                feePayable.setOilBaPay(BigDecimal.ZERO);
                feePayable.setOilFill(BigDecimal.ZERO);
                feePayable.setDeduct(BigDecimal.ZERO);
            });
            feePayableService.updateAllColumnBatchById(feePayableList);


            EntityWrapper<PrepayBill> prepayBillEw = new EntityWrapper<>();
            prepayBillEw.in("head_id", feeIdList);
            prepayBillService.delete(prepayBillEw);
        }
    }

    /**
     * 获取已有乙方名称
     */
    @Override
    public List<Object> getFleetTypeName() {
        List<Object> list = new ArrayList<>();
        EntityWrapper<Contract> e = new EntityWrapper<>();
        e.setSqlSelect("fleet_type_name");
        e.groupBy("fleet_type_name");
        List<Contract> contractList = this.selectList(e);
        // if (!CollectionUtils.isEmpty(contractList)) {
        // 	contractList.forEach(contract -> {
        // 		list.add(contract.getFleetTypeName());
        // 	});
        // }
        List<Object> objectList = this.selectObjs(e);
        if (!CollectionUtils.isEmpty(objectList)) {
            objectList.forEach(obj -> {
                list.add(obj.toString());
            });
        }
        return list;
    }

    /**
     * 新增合同以及附件
     *
     * @param contractVO
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void insertContractAndContractAccessories(ContractVO contractVO) {
        Contract contract = contractVO.getContract();

        if (Objects.isNull(contract)) {
            throw new BaseException("未获取合同信息");
        }
        bindContractByContractFleetDtls(contractVO.getContractFleetDtls(), contractVO.getContract());
        //合同可行性校验
        this.checkContractEffective(contract);
        //获取创建人
        if (Objects.nonNull(contract.getTenantId())) {
            new AccountBindUtil<Contract>().bindCreatorAndTenantId(contract, true);
        } else {
            new AccountBindUtil<Contract>().bindCreatorAndTenantId(contract, true);
        }
        Map<String, String> replaceChar = new HashMap<>();
        replaceChar.put("CCN", contractCodeMapping.get(contract.getFirstPartyName()));
        contract.setContCode(codeUtil.getContractCode().getNextCode(replaceChar));
        contract.setContState(0L);
        contract.setGmtCreate(new Date());
        // 2019-10-30 创建人
        JwtAccountVO account = AccountUtil.getAccountInfoFromSecurityContext();
        contract.setCreatorName(account.getUsername());
        boolean result = this.insert(contract);
        if (result) {
            contractFleetDtlService.insertContractFleetDtls(contractVO.getContractFleetDtls(), contract.getId());
            List<ContractAccessory> contractAccessories = contractVO.getContractAccessories();
            if (!CollectionUtils.isEmpty(contractAccessories)) {
                contractAccessories.forEach(contractAccessory -> {
                    contractAccessory.setHeadId(contract.getId());
                });
                contractAccessoryService.insertBatch(contractAccessories);
            }
        } else {
            throw new BaseException("新增合同异常");
        }
        // 校验出账规则是否时间冲突
        checkRuleDate(contract);
    }

    private void checkRuleDate(Contract contract) {
        if (org.apache.commons.lang3.StringUtils.isNotBlank(contract.getFleetIds())) {
            String[] split = contract.getFleetIds().split(",");
            if (split.length > 0) {
                List<String> fleetIdList = Arrays.asList(split);
                Integer existCount = chargeOffRuleService.getExistCount(fleetIdList, contract.getEffectiveDate(), contract.getInvalidDate());
                if (existCount != null && existCount > 0) {
                    throw new BaseException("当前乙方下已存在有效期冲突的规则, 会对后期审核带来影响, 请维护合同有效期!");
                }
            }
        }
    }

    /**
     * 根据合同主表id获取合同附件
     *
     * @param id
     * @return
     */
    @Override
    public List<ContractAccessory> getContractAccessoryByHeadId(Long id) {
        if (Objects.isNull(id)) {
            throw new BaseException("未获取合同id");
        }
        List<ContractAccessory> contractAccessories = null;
        EntityWrapper<ContractAccessory> contractAccessoryEntityWrapper = new EntityWrapper<>();
        contractAccessoryEntityWrapper.eq("head_id", id);
        contractAccessories = contractAccessoryService.selectList(contractAccessoryEntityWrapper);
        return contractAccessories;
    }

    /**
     * 根据合同id获取详明信息
     *
     * @param id
     * @return
     */
    @Override
    public ContractVO getContractDetail(Long id) {
        if (id == null) {
            throw new BaseException("请选定合同");
        }
        ContractVO contractVO = new ContractVO();
        contractVO.setContract(this.selectById(id));
        contractVO.setContractAccessories(this.getContractAccessoryByHeadId(id));
        contractVO.setContractFleetDtls(contractFleetDtlService.selectContractFleetDtlsByHeaderId(id));
        return contractVO;
    }

    /**
     * 下载附件
     *
     * @param id
     * @return
     */
    @Override
    public List<ContractAccessoryVO> upLoadContractAccessory(Long id) {
        List<ContractAccessoryVO> attachDetailVOS = new ArrayList<>();
        if (Objects.nonNull(id)) {
            EntityWrapper<ContractAccessory> e = new EntityWrapper<>();
            e.eq("head_id", id);
            List<ContractAccessory> contractAccessories = contractAccessoryService.selectList(e);
            if (!CollectionUtils.isEmpty(contractAccessories)) {
                contractAccessories.forEach(contractAccessory -> {
                    ContractAccessoryVO contractAccessoryVO = new ContractAccessoryVO();
                    AttachDetailVO attachDetailVO = new AttachDetailVO();
                    attachDetailVO.setAttachKey(contractAccessory.getFileKey());
                    attachDetailVO.setAttachName(contractAccessory.getFileName());
                    BeanUtils.copyProperties(uploadUtil.addAttachUploadResultNew(attachDetailVO), contractAccessoryVO);
                    BeanUtils.copyProperties(contractAccessory, contractAccessoryVO);
                    attachDetailVOS.add(contractAccessoryVO);
                });
            }
        }
        return attachDetailVOS;
    }

    /**
     * 合同的审核确认
     *
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Contract examine(Long id) {
        Contract contract = new Contract();
        try {
            /*
             * 验证原数据后修改状态
             */
            Contract oldContract = selectById(id);
            if (oldContract.getContState() == null && new Long(1).compareTo(oldContract.getContState()) != 0) {
                throw new BaseException("只能确认审核中的数据");
            }
            contract.setId(id);
            contract.setContState(2L);
            contract.setGmtModify(new Date());
            this.updateById(contract);
            // 临时合同生成规则
            if (Integer.valueOf(0).equals(oldContract.getContractType())) {
                List<Quote> quotes = quoteService.selectQuoteListByContractId(contract.getId());
                if (CollectionUtils.isEmpty(quotes)) {
                    throw new BaseException("无可用报价单");
                }
                quoteDtlService.updateFeePayableContactByHeaderId(oldContract, quotes.get(0).getId());
            }
            // 20181119-linbao-审核通过以后生成对应的出账规则
            createChargeRuleByContract(oldContract);
        } catch (BaseException e) {
            LOGGER.error("ContractServiceImpl.examine error: {}", e.getMessage());
            throw e;
        } catch (Exception e) {
            LOGGER.error("ContractServiceImpl.examine error: {}", e.getMessage());
            throw new BaseException("审核请求提交失败");
        }
        return contract;
    }

    /**
     * 根据合同生成出账规则
     * 1、运单状态只能是回单状态
     * 2、账单周期：正式合同为月、临时为天！
     * 3、账期为合同账期
     * 4、出账日：N、N+1、N+2都为1号。
     * 5、付款日期：N为当月15号，N+1为当月30号，N+2为次月30号；
     * 6、对账时效：N为10号，N+1为15号，N+2为20号
     * 7、收票时效：N为13号，N+1为20号，N+2为25号
     * 8、运输方式：和合同一致
     *
     * @param contract
     */
    private void createChargeRuleByContract(Contract contract) {
        if (Objects.deepEquals(contract.getContractType(), 1)) {
            List<ContractFleetDtl> fleetDtlList = contractFleetDtlService.selectContractFleetDtlsByHeaderId(contract.getId());
            if (!CollectionUtils.isEmpty(fleetDtlList)) {
                List<ChargeOffRule> ruleList = Lists.newArrayList();
                fleetDtlList.forEach(fleetDtl -> {
                    ChargeOffRule chargeOffRule = new ChargeOffRule();
                    // 运单状态 - 已回单
                    chargeOffRule.setStatus(ChargeOffRuleEnum.RULE_STATUS_RECEIPTED.getCode());
                    // 默认启动
                    chargeOffRule.setIsStart(ChargeOffRuleEnum.RULE_START.getCode());
                    if (Integer.valueOf(1).equals(contract.getContractType())) {
                        // 正式
                        chargeOffRule.setFleetAttribute(FleetAttributeEnum.OFFICIAL_ATTRIBUTE.getCode());
                        // 账期周期
                        chargeOffRule.setPayDayss(ChargeOffRuleEnum.PAY_PERIOD_MONTH.getCode());
                    } else if (Integer.valueOf(0).equals(contract.getContractType())) {
                        // 临时
                        chargeOffRule.setFleetAttribute(FleetAttributeEnum.TEMP_ATTRIBUTE.getCode());
                        // 账期周期
                        chargeOffRule.setPayDayss(ChargeOffRuleEnum.PAY_PERIOD_WEEK.getCode());
                    }
                    // 有效期
                    chargeOffRule.setEffectiveDate(contract.getEffectiveDate());
                    chargeOffRule.setInvalidDate(contract.getInvalidDate());
                    // 出账日
                    chargeOffRule.setChargeDays(Integer.valueOf(1));
                    // 车队id
                    chargeOffRule.setFleetId(fleetDtl.getFleetId());
                    // 车队名称
                    chargeOffRule.setFleetName(fleetDtl.getFleetName());
                    // 运输方式
                    chargeOffRule.setTransTypeId(contract.getShippingType());
                    // 根据运输方式获取对应的名称
                    chargeOffRule.setTransType(getServiceTypeNameById(contract.getShippingType()));
                    // 账期
                    chargeOffRule.setPayDays(contract.getPayDays());
                    // 创建时间
                    chargeOffRule.setGmtCreate(new Date());
                    // 创建人
                    JwtAccountVO jwtAccount = AccountUtil.getAccountInfoFromSecurityContext();
                    chargeOffRule.setCreator(Long.valueOf(jwtAccount.getAccountId()));
                    // 判断账期规则
                    setRuleByPayDay(chargeOffRule);
                    ruleList.add(chargeOffRule);
                });
                if (!CollectionUtils.isEmpty(ruleList)) {
                    chargeOffRuleService.insertBatch(ruleList);
                }
            }
        }
    }

    /**
     * * 4、出账日：N、N+1、N+2都为1号。
     * * 5、付款日期：N为当月15号，N+1为当月30号，N+2为次月30号；
     * * 6、对账时效：N为10号，N+1为15号，N+2为20号
     * * 7、收票时效：N为13号，N+1为20号，N+2为25号
     *
     * @param chargeOffRule
     */
    private void setRuleByPayDay(ChargeOffRule chargeOffRule) {
        if (ChargeOffRuleEnum.PAY_DAY_N.getCode().equals(chargeOffRule.getPayDays())) {
            // N
            // 付款日期
            chargeOffRule.setPayment(ChargeOffRuleEnum.PAYMENT_2.getCode());
            // 对账失效
            chargeOffRule.setRecAging(ChargeOffRuleEnum.REC_0.getCode());
            // 收票失效
            chargeOffRule.setInvoiceAging(ChargeOffRuleEnum.INVOICE_REC_0.getCode());
        } else if (ChargeOffRuleEnum.PAY_DAY_N_1.getCode().equals(chargeOffRule.getPayDays())) {
            // N+1
            // 付款日期
            chargeOffRule.setPayment(ChargeOffRuleEnum.PAYMENT_1.getCode());
            // 对账失效
            chargeOffRule.setRecAging(ChargeOffRuleEnum.REC_1.getCode());
            // 收票失效
            chargeOffRule.setInvoiceAging(ChargeOffRuleEnum.INVOICE_REC_1.getCode());
        } else if (ChargeOffRuleEnum.PAY_DAY_N_2.getCode().equals(chargeOffRule.getPayDays())) {
            // N+2
            // 付款日期
            chargeOffRule.setPayment(ChargeOffRuleEnum.PAYMENT_0.getCode());
            // 对账失效
            chargeOffRule.setRecAging(ChargeOffRuleEnum.REC_2.getCode());
            // 收票失效
            chargeOffRule.setInvoiceAging(ChargeOffRuleEnum.INVOICE_REC_2.getCode());
        }
    }

    /**
     * 获取对应的运输方式名称
     *
     * @param id
     * @return
     */
    private String getServiceTypeNameById(Long id) {
        List<ServiceTypeDTO> allServiceTypeList = mdmUtil.getAllServiceTypeList();
        if (!CollectionUtils.isEmpty(allServiceTypeList)) {
            for (int i = 0, n = allServiceTypeList.size(); i < n; i++) {
                if (allServiceTypeList.get(i).getId().equals(id)) {
                    return allServiceTypeList.get(i).getValue();
                }
            }
        }
        return null;
    }

    /**
     * 根据Code查询对应的合同
     *
     * @param code
     * @return
     */
    @Override
    public Contract selectContractByCode(String code) {
        EntityWrapper<Contract> contractEntityWrapper = new EntityWrapper<>();
        contractEntityWrapper.eq("cont_code", code);
        List<Contract> contracts = baseMapper.selectListNoTenant(contractEntityWrapper);
        return CollectionUtils.isEmpty(contracts) ? null : contracts.get(0);
    }

    /**
     * 获取需要打印的合同详情信息
     *
     * @param contractId
     * @return
     */
    @Override
    public PrintContractVO selectPrintContractDetail(Long contractId) {

        PrintContractVO printContractVO = new PrintContractVO();
        Contract contractDetail = this.selectById(contractId);
        ContractAndFinalpayVO contractAndFinalpayVO = new ContractAndFinalpayVO();
        BeanUtils.copyProperties(contractDetail, contractAndFinalpayVO);
        contractAndFinalpayVO.setFinalpayRateSum(
                (contractAndFinalpayVO.getCashFinalpayRate() == null ? BigDecimal.ZERO : contractAndFinalpayVO.getCashFinalpayRate()).add
                        (contractAndFinalpayVO.getOilFinalpayRate() == null ? BigDecimal.ZERO : contractAndFinalpayVO.getOilFinalpayRate())
        );
        contractAndFinalpayVO.setPrepayRateSum(
                (contractAndFinalpayVO.getCashPrepayRate() == null ? BigDecimal.ZERO : contractAndFinalpayVO.getCashPrepayRate()).add
                        (contractAndFinalpayVO.getOilPrepayRate() == null ? BigDecimal.ZERO : contractAndFinalpayVO.getOilPrepayRate())
        );
        printContractVO.setContractAndFinalpayVO(contractAndFinalpayVO);
        QuoteAndDtlVO quoteAndDtlVO = quoteService.selectQuoteAndDtlByContractId(contractId);
        if (quoteAndDtlVO != null && !CollectionUtils.isEmpty(quoteAndDtlVO.getQuoteDtls())) {
            List<QuoteDtlAndFeeVO> quoteDtlAndFeeVOS = new ArrayList<>();
            BigDecimal sumQuotationAmt = new BigDecimal("0");
            for (QuoteDtl quoteDtl : quoteAndDtlVO.getQuoteDtls()) {
                QuoteDtlAndFeeVO quoteDtlAndFeeVO = new QuoteDtlAndFeeVO();
                BeanUtils.copyProperties(quoteDtl, quoteDtlAndFeeVO);
                FeePayable feePayable = feePayableService.selectById(quoteDtlAndFeeVO.getFeeId());
                if (feePayable != null) {
                    quoteDtlAndFeeVO.setOrderDate(feePayable.getOrderDate());
                    quoteDtlAndFeeVO.setWayBillId(feePayable.getWaybillId());
                }
                quoteDtlAndFeeVO.getQuotationPrice();
                quoteDtlAndFeeVO.getQuotationMileage();
                quoteDtlAndFeeVO.setQuotationAmt(
                        (quoteDtlAndFeeVO.getQuotationPrice() == null ? BigDecimal.ZERO : quoteDtlAndFeeVO.getQuotationPrice()).multiply(
                                (quoteDtlAndFeeVO.getQuotationMileage() == null ? BigDecimal.ZERO : quoteDtlAndFeeVO.getQuotationMileage()))
                );
                sumQuotationAmt = sumQuotationAmt.add(quoteDtlAndFeeVO.getQuotationAmt());
                quoteDtlAndFeeVOS.add(quoteDtlAndFeeVO);
            }
            quoteAndDtlVO.setDtlQuotationAmtSum(sumQuotationAmt);
            quoteAndDtlVO.setQuoteDtlAndFeeVOS(quoteDtlAndFeeVOS);
            quoteAndDtlVO.setQuoteDtls(null);
        }
        printContractVO.setQuoteAndDtlVO(quoteAndDtlVO);
        return printContractVO;
    }
}
